package com.naiterui.ehp.bs.doctor.interceptor;

import com.naiterui.common.redis.RedisUtil;
import com.naiterui.ehp.bp.constants.CommonConstant;
import com.naiterui.ehp.bp.domain.Doctor;
import com.naiterui.ehp.bp.domain.Login;
import com.naiterui.ehp.bp.support.exception.PublicService;
import com.naiterui.ehp.bp.support.security.HeaderConstant;
import com.naiterui.ehp.bp.support.security.SettingConfig;
import com.naiterui.ehp.bp.support.utils.JsonMapper;
import com.naiterui.ehp.bp.utils.context.SpringContextHolder;
import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bs.doctor.dao.IDoctorDao;
import com.naiterui.ehp.bs.doctor.dao.ILoginDao;
import com.naiterui.ehp.bs.doctor.exception.ExceptionCodes;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author guoyongxiang
 * @date 2019-06-22 13:05
 * @since 1.0.0
 */
public class PasswordExpireInterceptor implements HandlerInterceptor {

    private static final Logger LOGGER = LoggerFactory.getLogger(PasswordExpireInterceptor.class);

    private static final String RDS_KEY_LAST_MODIFY = CommonConstant.REDIS_PRE_DR + "lastModify_";
    private static final int RDS_KEY_LAST_MODIFY_EXPIRE = 10 * 60;

    private static String[] NOCHECK_URI = {
            // 客户端升级&升级配置JSP
            "/ad/checkVersion",
            "/ad/saveVersion",
            "/ad/saveH5Version",

            // 登录 & 注册 & 获取短信验证码
            "/ad/login",
            "/ad/login/*",
            "/ad/sendSms",
            "/ad/time.jsp",

            // 获取首页启动图信息
            "/ad/index/startInfo",

            // H5分享二维码
            "/ad/auth/getAppSpreadInfo",

            // B2C使用
            "/ad/api/recdrug/usage",

            // 客户端基础配置
            "/ad/doctorInfo/doctorConfig",
            "/ad/doctorInfo/globalConfig",
            "/ad/index/noticeDetail",

            // 客户端活动页JS
            "/ad/medication/salePrice"
    };

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // ************************************Header 参数获取**************************************
        // 平台
        String platform = request.getHeader(HeaderConstant.HEADER_PLATFORM);
        // 来源
        String origin = request.getHeader(HeaderConstant.HEADER_ORIGIN);
        // URL
        String url = request.getServletPath();
        String doctorIdStr = request.getParameter(SettingConfig.DOCTOR_ID);
        Integer focreModifyDay = ConfigUtil.getInt("dr.password.modify.force.day");

        // 仅校验医生端
        if (!(HeaderConstant.HEADER_ORIGIN_DOCTOR_APP + "").equals(origin) || focreModifyDay == null || focreModifyDay == 0) {
            return true;
        }
        // 校验医生ID
        if (!StringUtils.isNumeric(doctorIdStr) || checkVersionIgnoreUrl(url)) {
            return true;
        }
        // 校验密码过期
        Date lastModify = getDoctorLastPasswordModify(response, Long.valueOf(doctorIdStr));
        if (lastModify == null) {
            stuffErrorCode(response, ExceptionCodes.USER_NOT_EXIST);
            return false;
        }
        Date expireDate = DateUtil.addDays(lastModify, focreModifyDay);
        if (System.currentTimeMillis() > expireDate.getTime()) {
            stuffErrorCode(response, ExceptionCodes.PWD_EXPIRE_ERROR);
            return false;
        }

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {

    }

    /**
     * 校验免校验列表
     * LoginInterceptor.checkVersionIgnoreUrl()
     *
     * @param reqUrl
     *
     * @return
     *
     * @Author guoyongxiang
     * @Date 2017年6月28日
     * @since 2.8.0
     */
    private static boolean checkVersionIgnoreUrl(String reqUrl) {
        for (String uri : NOCHECK_URI) {
            if (matchUrl(uri, reqUrl)) {
                return true;
            }
        }
        return false;
    }


    /**
     * 匹配URL
     * LoginInterceptor.matchUrl()
     *
     * @param matchUrl 匹配规则(左匹配支持*)
     * @param reqUrl   被检测URL
     *
     * @return
     *
     * @Author guoyongxiang
     * @Date 2017年6月28日
     * @since 2.8.0
     */
    private static boolean matchUrl(String matchUrl, String reqUrl) {
        Pattern pattern = Pattern.compile(matchUrl);
        Matcher matcher = pattern.matcher(reqUrl);
        return matcher.lookingAt();
    }

    private Date getDoctorLastPasswordModify(HttpServletResponse response, Long doctorId) {
        Date doctorLastModify = (Date) RedisUtil.valueOps().getObject(RDS_KEY_LAST_MODIFY + doctorId);
        if (doctorLastModify == null) {
            IDoctorDao doctorDao = SpringContextHolder.getBean("adDoctorDaoImpl", IDoctorDao.class);
            ILoginDao loginDao = SpringContextHolder.getBean("adLoginDaoImpl", ILoginDao.class);
            Doctor doctor = doctorDao.get(doctorId);
            if (doctor == null) {
                LOGGER.warn("医生ID不存在 doctorId:{}", doctorId);
                return null;
            }
            Login login = loginDao.get(doctor.getUserId());
            if (login.getLastPwdModify() != null) {
                setDoctorLastPasswordModifyCache(doctorId, login.getLastPwdModify());
                doctorLastModify = login.getLastPwdModify();
            }
        }
        return doctorLastModify;
    }

    /**
     * 设置改密缓存
     *
     * @param doctorId
     * @param modifyTime
     */
    public static void setDoctorLastPasswordModifyCache(Long doctorId, Date modifyTime) {
        RedisUtil.valueOps().setObject(RDS_KEY_LAST_MODIFY + doctorId, modifyTime, RDS_KEY_LAST_MODIFY_EXPIRE);
    }

    private void stuffErrorCode(HttpServletResponse response, int errorCode) throws IOException {
        if (null == response) {
            return;
        }
        response.getWriter().println(JsonMapper.toJson(PublicService.returnResponseVO(errorCode)));
    }

}
